#include "pch.h"
#include "semaphore_cpp11.h"
#include <condition_variable>
#include <mutex>
#include <thread>

struct semaphore_c11::Impl{
    std::mutex _mutex;
	std::condition_variable _condition;
};

semaphore_c11::semaphore_c11():
    _count(0)
    ,_pImpl(new Impl)
{
}

semaphore_c11::~semaphore_c11()
{
    _pImpl->_condition.notify_all();
}

void semaphore_c11::signal()
{
    {
        std::lock_guard<decltype(_pImpl->_mutex)> lock(_pImpl->_mutex);
        ++_count;
    }
    _pImpl->_condition.notify_one();
}

void semaphore_c11::wait()
{
    std::unique_lock<decltype(_pImpl->_mutex)> lock(_pImpl->_mutex);
    while (!_count) // Handle spurious wake-ups.
        _pImpl->_condition.wait(lock);

    --_count;
}

bool semaphore_c11::try_wait(int timeOut)
{
    std::unique_lock<decltype(_pImpl->_mutex)> lock(_pImpl->_mutex);
    if(_pImpl->_condition.wait_for(lock, std::chrono::milliseconds(timeOut), [this]{return _count != 0;}))
    {
        --_count;
        return true;
    }
    return false;
}
